import numpy as np

class KNN:
    def __init__(self, k=3):
        self.k = k
        self.X_train = None
        self.y_train = None
        self.X_test = None  
        self.y_test = None  
    
    def load_iris(self, file_path="iris.data"):
        data = []
        with open(file_path, 'r') as f:
            for line in f:
                if line.strip():
                    parts = line.strip().split(',')
                    features = list(map(float, parts[:4]))
                    label = parts[4]
                    label_map = {'Iris-setosa': 0, 'Iris-versicolor': 1, 'Iris-virginica': 2}
                    data.append(features + [label_map[label]])
        data = np.array(data)
        X = data[:, :4]
        y = data[:, 4].astype(int)
        self.X_train, self.X_test = X[:120], X[120:]
        self.y_train, self.y_test = y[:120], y[120:]
        return self.X_train, self.X_test, self.y_train, self.y_test
    
    def euclidean_distance(self, x1, x2):
        return np.sqrt(np.sum((x1 - x2) **2))
    
    def predict(self, X_test):
        y_pred = []
        for test_sample in X_test:
            distances = [self.euclidean_distance(test_sample, train_sample) for train_sample in self.X_train]
            k_indices = np.argsort(distances)[:self.k]
            k_labels = [self.y_train[i] for i in k_indices]
            unique_labels, counts = np.unique(k_labels, return_counts=True)
            y_pred.append(unique_labels[np.argmax(counts)])
        return np.array(y_pred)
    
    def evaluate(self, y_pred):
        accuracy = np.sum(y_pred == self.y_test) / len(self.y_test)
        return accuracy

if __name__ == "__main__":
    knn = KNN(k=5)
    knn.load_iris()
    y_pred = knn.predict(knn.X_test)
    accuracy = knn.evaluate(y_pred)

    label_map_rev = {
        0: 'Iris-setosa',
        1: 'Iris-versicolor',
        2: 'Iris-virginica'
    }

    y_test_names = [label_map_rev[label] for label in knn.y_test]
    y_pred_names = [label_map_rev[label] for label in y_pred]

    print("===== 测试集分类结果 =====")
    for i in range(len(y_test_names)):
        result = "正确" if y_test_names[i] == y_pred_names[i] else "错误"
        print(f"样本{i+1}:")
        print(f"  真实类别: {y_test_names[i]}")
        print(f"  预测类别: {y_pred_names[i]}")
        print(f"  结果: {result}\n")

    print(f"===== 模型评估 =====")
    print(f"KNN准确率: {accuracy:.2f} (共{len(knn.y_test)}个测试样本)")